using Moq;
using NUnit.Framework;
using TDUnit.Common.ScriptEngine;
using TDUnit.Common.ScriptExecutionEngine;
using TDUnit.Common.TestData;
using TDUnit.Common.TestDataParser;
using TDUnit.Loggers;

namespace TDUnit.Tests
{
    [TestFixture]
    public class TestDataUtilityTests
    {
        private Mock<ITestDataParser> mockParser;
        private Mock<IScriptEngine> mockScriptEngine;
        private Mock<IScriptExecutionEngine> mockExecutionEngine;

        private TestDataUtility utility;

        #region SetUp
        [SetUp]
        public void SetUp()
        {
            mockParser = new Mock<ITestDataParser>(MockBehavior.Strict);
            mockScriptEngine = new Mock<IScriptEngine>(MockBehavior.Strict);
            mockExecutionEngine = new Mock<IScriptExecutionEngine>(MockBehavior.Strict);

            utility = new TestDataUtility(mockParser.Object, mockExecutionEngine.Object, mockScriptEngine.Object, new NullLogger());
        }
        #endregion

        #region Create test data tests

        [Test]
        public void CreateSimpleTestDataWithNoAutoIdentity()
        {
            var ds = CreateSimpleTestDataSet("1", false);
            mockParser.Expect(parser => parser.Parse()).Returns(ds);
            mockScriptEngine.Expect(script => script.GetInsertScriptForRow(ds.Tables[0].Rows[0])).Returns(string.Empty);
            mockExecutionEngine.Expect(engine => engine.ExecuteNonQueryScript(string.Empty));

            utility.SetUp();
        }

        [Test]
        public void CreateSimpleTestDataWithAutoIdentity()
        {
            var ds = CreateSimpleTestDataSet(string.Empty, true);
            mockParser.Expect(parser => parser.Parse()).Returns(ds);
            mockScriptEngine.Expect(script => script.GetInsertScriptForRow(ds.Tables[0].Rows[0])).Returns(string.Empty);
            mockExecutionEngine.Expect(engine => engine.ExecuteNonQueryScript(string.Empty));
            mockScriptEngine.Expect(script => script.GetSelectAutoIdentityScript()).Returns(string.Empty);
            mockExecutionEngine.Expect(engine => engine.ExecuteScalarQueryScript(string.Empty)).Returns("1");

            utility.SetUp();

            Assert.AreEqual("1", ds.Tables[0].Rows[0].PrimaryKeyColumn.Value);
        }

        #endregion

        #region Delete test data tests

        [Test]
        public void DeleteSimpleTestData()
        {
            var ds = CreateSimpleTestDataSet("ID", true);

            mockParser.Expect(parser => parser.Parse()).Returns(ds);
            mockScriptEngine.Expect(script => script.GetDeleteScriptForRow(ds.Tables[0].Rows[0])).Returns(string.Empty);
            mockExecutionEngine.Expect(engine => engine.ExecuteNonQueryScript(string.Empty));

            utility.TearDown();
        }

        [Test]
        public void DeleteTestDataWithChildRow_ChildRowShouldBeDeletedFirst()
        {
            var ds = CreateSimpleTestDataSet("1", true);
            ds.AddTable("TableTwo", "ID").AddRow(new PrimaryKeyColumn("ID")).AddColumn("ColumnOne");
            ds.GetTable("TableTwo").AddRow(new PrimaryKeyColumn("ID")).AddColumn("ColumnOne");

            mockParser.Expect(parser => parser.Parse()).Returns(ds);
            mockScriptEngine.Expect(script => script.GetDeleteScriptForRow(ds.Tables[1].Rows[1])).Returns(string.Empty);
            mockExecutionEngine.Expect(engine => engine.ExecuteNonQueryScript(string.Empty));
            mockScriptEngine.Expect(script => script.GetDeleteScriptForRow(ds.Tables[1].Rows[0])).Returns(string.Empty);
            mockExecutionEngine.Expect(engine => engine.ExecuteNonQueryScript(string.Empty));
            mockScriptEngine.Expect(script => script.GetDeleteScriptForRow(ds.Tables[0].Rows[0])).Returns(string.Empty);
            mockExecutionEngine.Expect(engine => engine.ExecuteNonQueryScript(string.Empty));

            utility.TearDown();
        }

        #endregion

        #region Helper Methods

        private static TestData CreateSimpleTestDataSet(string pkValue, bool isAutoIdent)
        {
            var ds = new TestData();
            ds.AddTable("TableName", "ID").WithAutoIdentity(isAutoIdent).AddRow(new PrimaryKeyColumn("ID")).PrimaryKeyColumn.WithValue(pkValue);
            return ds;
        }

        #endregion
    }
}